package com.ala4.oxcafe.boot;

import com.ala4.oxcafe.boot.filter.PasswordAuthenticationFilter;
import com.ala4.oxcafe.boot.filter.WeChatAuthenticationFilter;
import com.ala4.oxcafe.boot.handler.LoginFailureHandler;
import com.ala4.oxcafe.boot.handler.LoginSuccessHandler;
import com.ala4.oxcafe.boot.handler.UserLogoutSuccessHandler;
import com.ala4.oxcafe.boot.manager.UserTokenManager;
import com.ala4.oxcafe.boot.provider.WeChatAuthenticationProvider;
import com.ala4.oxcafe.boot.userdetails.PasswordUserDetailsService;
import com.ala4.oxcafe.boot.userdetails.WeChatUserDetailsService;
import com.ala4.oxcafe.properties.SecurityProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 配置spring security拦截器连
 *
 * @author PING
 * @date 2025/8/11 22:01
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class AuthorizationServerConfig {

    /**
     * 配置密码解析器,根据前缀委派给对应的实现
     *
     * @return BCryptPasswordEncoder
     */
    @Bean
    @ConditionalOnMissingBean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }


    /**
     * 配置端点的过滤器链
     *
     * @param http spring security核心配置类
     * @return 过滤器链
     * @throws Exception 抛出
     */
    @Bean
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http,
                                                                      SecurityProperties securityProperties,
                                                                      UserTokenManager userTokenManager,
                                                                      PasswordUserDetailsService passwordUserDetailsService,
                                                                      WeChatUserDetailsService weChatUserDetailsService) throws Exception {

        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);

        // 添加密码登录的provider
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(passwordUserDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationManagerBuilder.authenticationProvider(daoAuthenticationProvider);
        // 添加微信登录的provider
        WeChatAuthenticationProvider weChatAuthenticationProvider = new WeChatAuthenticationProvider(weChatUserDetailsService);
        authenticationManagerBuilder.authenticationProvider(weChatAuthenticationProvider);

        // 生成AuthenticationManager对象
        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();

        // 禁用 csrf 与 cors
        http.csrf(AbstractHttpConfigurer::disable);
        http.cors(AbstractHttpConfigurer::disable);

        // 授权服务器只管理登录和登出URL
        http.securityMatcher(securityProperties.getPasswordLoginUrl(), securityProperties.getWxLoginUrl(), securityProperties.getLogoutUrl());

        // 没有session
        http.sessionManagement(sessionManage -> sessionManage.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        // 禁用默认的form表单登录
        http.formLogin(AbstractHttpConfigurer::disable).logout(logout -> {
            logout.logoutUrl(securityProperties.getLogoutUrl());
            logout.logoutSuccessHandler(new UserLogoutSuccessHandler(userTokenManager));
        });
        // 设置manager是我们自定义的
        http.authenticationManager(authenticationManager);

        // 添加密码登录拦截器 拦截密码登录的流程
        http.addFilterBefore(passwordAuthenticationFilter(authenticationManager, userTokenManager, securityProperties), UsernamePasswordAuthenticationFilter.class);

        // 添加微信登录拦截器 拦截微信登录的流程
        http.addFilterBefore(weChatAuthenticationFilter(authenticationManager, userTokenManager, securityProperties), UsernamePasswordAuthenticationFilter.class);

        // 验证码登录拦截器
//        http.addFilterBefore(new CaptchaAuthenticationFilter(new LoginFailureHandler(), userTokenManager, customSecurityProperties), JsonUsernamePasswordAuthenticationFilter.class);

        return http.build();


    }

    /**
     * 配置密码登录过滤器
     *
     * @param userTokenManager
     * @param securityProperties
     * @return
     * @throws Exception
     */
    public PasswordAuthenticationFilter passwordAuthenticationFilter(AuthenticationManager authenticationManager,
                                                                     UserTokenManager userTokenManager,
                                                                     SecurityProperties securityProperties) {


        PasswordAuthenticationFilter passwordAuthenticationFilter = new PasswordAuthenticationFilter(authenticationManager);
        // 配置认证时的各种回调处理器
        passwordAuthenticationFilter.setAuthenticationSuccessHandler(new LoginSuccessHandler(userTokenManager));
        passwordAuthenticationFilter.setAuthenticationFailureHandler(new LoginFailureHandler());
        passwordAuthenticationFilter.setFilterProcessesUrl(securityProperties.getPasswordLoginUrl());
        passwordAuthenticationFilter.setUsernameParameter(securityProperties.getUsernameParameter());
        passwordAuthenticationFilter.setPasswordParameter(securityProperties.getPasswordParameter());
        return passwordAuthenticationFilter;
    }

    /**
     * 配置微信登录拦截器
     *
     * @param userTokenManager
     * @param securityProperties
     * @return
     * @throws Exception
     */
    public WeChatAuthenticationFilter weChatAuthenticationFilter(AuthenticationManager authenticationManager,
                                                                 UserTokenManager userTokenManager,
                                                                 SecurityProperties securityProperties) {


        WeChatAuthenticationFilter weChatAuthenticationFilter = new WeChatAuthenticationFilter(authenticationManager);
        // 配置认证时的各种回调处理器
        weChatAuthenticationFilter.setAuthenticationSuccessHandler(new LoginSuccessHandler(userTokenManager));
        weChatAuthenticationFilter.setAuthenticationFailureHandler(new LoginFailureHandler());
        weChatAuthenticationFilter.setFilterProcessesUrl(securityProperties.getWxLoginUrl());
        return weChatAuthenticationFilter;
    }


}
